package cn.com.demo.crl;

import org.bouncycastle.asn1.x509.CRLNumber;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.x509.X509V2CRLGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;

import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.Date;

/**
 * CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
 * <p>
 * DistributionPoint ::= SEQUENCE {
 * distributionPoint       [0] DistributionPointName OPTIONAL,
 * reasons                 [1] ReasonFlags OPTIONAL,
 * cRLIssuer               [2] GeneralNames OPTIONAL }
 * <p>
 * ReasonFlags ::= BIT STRING {
 * unused                   (0),
 * keyCompromise            (1),
 * cACompromise             (2),
 * affiliationChanged       (3),
 * superseded               (4),
 * cessationOfOperation     (5),
 * certificateHold          (6),
 * privilegeWithdrawn       (7),
 * aACompromise             (8) }
 * <p>
 * DistributionPointName ::= CHOICE {
 * fullName                [0] GeneralNames,
 * nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
 * <p>
 * CertificateList ::= SEQUENCE {
 * tbsCertList         TBSCertList,
 * signatureAlgorithm  AlgorithmIdentifier,
 * signature           BIT STRING }
 * <p>
 * TBSCertList ::= SEQUENCE {
 * version               Version OPTIONAL,
 * -- if present, must be v2
 * signature             AlgorithmIdentifier,
 * issuer                Name,
 * thisUpdate            Time,
 * nextUpdate            Time OPTIONAL,
 * revokedCertificates   SEQUENCE OF SEQUENCE {
 * userCertificate      CertificateSerialNumber,
 * <p>
 * revocationDate        Time,
 * crlEntryExtensions    Extensions OPTIONAL
 * -- if present, must be v2 } OPTIONAL,
 * crlExtensions        [0] EXPLICIT Extensions OPTIONAL
 * -- if present, must be v2 }
 * <p>
 * reasonCode ::= { CRLReason }
 * <p>
 * CRLReason ::= ENUMERATED {
 * unspecified             (0),
 * keyCompromise           (1),
 * cACompromise            (2),
 * affiliationChanged      (3),
 * superseded              (4),
 * cessationOfOperation    (5),
 * certificateHold         (6),
 * removeFromCRL           (8),
 * privilegeWithdrawn      (9),
 * aACompromise            (10) }
 * <p>
 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
 * <p>
 * Extension ::= SEQUENCE {
 * extnID    OBJECT IDENTIFIER,
 * critical  BOOLEAN DEFAULT FALSE,
 * extnValue OCTET STRING }
 *
 * @author yuanzhenchao
 */
public class X509CRLExample {

    public static X509CRL createX509crl(
            X509Certificate caCert,
            PrivateKey caKey,
            BigInteger revokedSerialNumber
    ) throws Exception {
        X509V2CRLGenerator crlGen = new X509V2CRLGenerator();

        Date now = new Date();

        crlGen.setIssuerDN(caCert.getSubjectX500Principal());
        crlGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
        crlGen.setThisUpdate(now);
        crlGen.setNextUpdate(new Date(now.getTime() + 100000));

        crlGen.addCRLEntry(revokedSerialNumber, now, org.bouncycastle.asn1.x509.CRLReason.privilegeWithdrawn);
        crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier,
                false, new AuthorityKeyIdentifierStructure(caCert));
        crlGen.addExtension(X509Extensions.CRLNumber,
                false, new CRLNumber(BigInteger.valueOf(1)));

        return crlGen.generate(caKey, "BC");
    }

    /**
     * @param args
     */
    public static void main(String[] args) {

    }

}
